#supervised the process 
#define number of bots
#assign them to the matrix road network randomly
#control the bots location and communications

import random

colonyDetails=[] #hold colony outputs
    
#run the simulation
def runSimulation(botDetails,roadSizeX,roadSizeY,roadNetwork):
   
            
       
    intraCommunication(botDetails,roadSizeX,roadSizeY);
    interCommunication(botDetails)
        
    print 'enter 1 for do another iteration:';
    print 'enter 2 for make movement of the vehicles:'
    print 'enter 3 for refresh the data tables:'
    cont = raw_input('Enter e for exit:');
    if cont=='1':
        #show the road matrix   
        #showMatrix(botDetails,roadSizeX,roadSizeY);
        runSimulation(botDetails,roadSizeX, roadSizeY);
    if cont=='2':
        makeMove(botDetails,roadSizeX,roadSizeY); 
        #show the road matrix   
        #showMatrix(botDetails,roadSizeX,roadSizeY);
        runSimulation(botDetails,roadSizeX, roadSizeY);
    
    if cont=='3':
        makeMove(botDetails,roadSizeX,roadSizeY); 
        #show the road matrix   
        #showMatrix(botDetails,roadSizeX,roadSizeY);
        runSimulation(botDetails,roadSizeX, roadSizeY);
        
    if cont!='e':
        makeMove(botDetails,roadSizeX,roadSizeY); 
        runSimulation(botDetails,roadSizeX, roadSizeY);
        
        #print 'id='+str(bots.id)
        #print 'list'
        # for i in inRangeList:
        #  print i.id 

#handle the intra communication of the colony
def intraCommunication(botsList,roadSizeX,roadSizeY):
   
    #get all the colonies
    colony=findColony(botsList,roadSizeX,roadSizeY);
    #define the token bot of each colony
    tokens=defineToken(colony)
    #show the road matrix   
    showMatrix(botsList,roadSizeX,roadSizeY);
    for bots in botsList:
        adjacency=getAdjacencyElements(roadSizeX,roadSizeY, bots.location[0],bots.location[1])
        inRangeList=[bot for bot in botsList if any(e[0]==bot.location[0] and e[1]==bot.location[1]for e in adjacency)]
        #inRangeList=[bot for bot in botsList if bot.location[1]>=bots.location[1]-2 and bot.location[1]<=bots.location[1]+2 and bot.location[0]<=bots.location[0]+2 and bot.location[0]>=bots.location[0]-2 and bots.id!=bot.id] 
        
        
        
        #if token available for current bot->set it
        if(any(token==bots.id for token in tokens)):
            bots.token=True
            
        
        #update data table
        for eachBot in inRangeList:
            
            bots.createTable(eachBot.getTable())
            
            
            
        print '------------------ bot'+str(bots.id)+'---------------\ndata table :'
        print bots.getTable()
        print 'average speed :\n'+str(bots.findAverageSpeed())+'\nlocation :'
        print bots.findMedianLocation()
        if(bots.token==True):
            print 'i have token.. please implement broadcast function for broadcast colony details'
            bots.token=False#remove token from the bot
            
            #add colony information to the inter communication link
            location=bots.findMedianLocation()
            print location
            #format [[v1,location1,number of bots],[v2,location2,number of bots],...]
            colonyDetails.append([bots.findAverageSpeed(),location,bots.findNumberOfVehicles()])
            
        print '\n-------------------------------\n'


#inter communication link
def interCommunication(botsList):
    
    #get bot one by one from the bots list
    for bot in botsList:
        #give colony detail one by one to the bot
        for colony in colonyDetails:
            bot.inputColonyDetails(colony)
            
        print '********graph of the colony of bot '+str(bot.id)+'**********'
        print bot.drawMap()
        print '************************************************************'

#find the all colony
def findColony(botDetails,roadSizeX,roadSizeY):
    colony={}
    for bots in botDetails:
        adjacency=getAdjacencyElements(roadSizeX,roadSizeY, bots.location[0],bots.location[1])
        inRangeList=[bot.id for bot in botDetails if any(e[0]==bot.location[0] and e[1]==bot.location[1]for e in adjacency)]

        #append current iterator bot to the range list as well
        inRangeList.append(bots.id) 
         
        for each in inRangeList:
            #find the key which contain certain value
            colonyId=[k for k, v in colony.iteritems() if any(x==each for x in v)]
            
        #find the colonies    
        if(colonyId==[]):
            if(colony.__len__()<1):
                    colony={1:inRangeList}
            else:
                    colony[max(colony, key=int)+1]=inRangeList
        else:
            colony[colonyId[0]]=list(set(colony[colonyId[0]]+inRangeList))
            
            
    return colony
                
#define the token of each colony
def defineToken(colony):
    tokens=[]
    #get all the keys
    keys=[k for k, v in colony.iteritems()]
    for each in keys:
        #define token randomly
        values=colony[each]
        token=random.randrange(0,len(values))
        #append token bot id to the return value
        tokens.append(values[token])     
    return tokens

#print the matrix in an understandable format          
def showMatrix(botDetails,roadSizeX,roadSizeY):
    buckets = [[0 for col in range(roadSizeY)] for row in range(roadSizeX)];
    #x=1;
    for bot in botDetails:
        buckets[bot.location[0]][bot.location[1]]=bot.id;
        #print buckets;
        #x+=1;
    for row in buckets:
        print row;
        #x+=1;

#move bots randomly around it by 1 unit       
def makeMove(botDetails,roadSizeX,roadSizeY):
    assigned=[];#already assigned movements(avoid overlap each other)
    for position in botDetails:
        #print position;
        temp=[[0,1],[0,-1],[1,0],[-1,0]];
        
        while len(temp)>0:
            location=random.randrange(0,len(temp));
            #position.location=[position.location[0]+temp[location][0],position.location[1]+temp[location][1]];
            row=position.location[0]+temp[location][0];
            col=position.location[1]+temp[location][1]
            temp.remove(temp[location]);
            if row<0 or col<0 or row>=roadSizeX or col>=roadSizeY or assigned.__contains__([row,col]):
                
                continue;
            else:
                position.location=[row,col];
                assigned.append([row,col]);
                break;
       
        #print position.location;


    



         
#return adjacency elements of range 2 units         
def getAdjacencyElements( xmax, ymax, x, y ):
    results = []
    for dx in [-2,-1,0,1,2]:
        for dy in [-2,-1,0,1,2]:
            newx = x+dx
            newy = y+dy
            if (dx == 0 and dy == 0):
                continue
            if (newx>=0 and newx<xmax and newy >=0 and newy<ymax):
                results.append( (newx, newy) )
    return results
